﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Dominio
{
    public class Sistema
    {
        private static Sistema dominio;

        private List<ICommand> commandos;

        internal List<ICommand> Commandos
        {
            get { return commandos; }
            set { commandos = value; }
        }

        private List<Plugin> pluginsList;

        public List<Plugin> PluginsList
        {
            get { return pluginsList; }
            set { pluginsList = value; }
        }

        private List<OPersistente> cuentasList;

        internal List<OPersistente> CuentasList
        {
            get { return cuentasList; }
            set { cuentasList = value; }
        }

        private Sistema()
        {
            Commandos = new List<ICommand>();
            PluginsList = new List<Plugin>();
            CuentasList = new List<OPersistente>();
        }

        public Sistema Dominio
        {
            get { return dominio; }
            set { dominio = value; }
        }

        public static Sistema GetInstance()
        {
            if (dominio == null)
            {
                dominio = new Sistema();
            }
            return dominio;
                
        }

        public void CargarSistema()
        {
            Cuenta c = new Cuenta();
            List<OPersistente> cuentas = null;
            cuentas = c.TraerLista();
            foreach(Cuenta cuenta in cuentas)
            {
                //cuenta.RecuperarDatos();

                Usuario usuario = cuenta.Usuario;
                usuario.RecuperarDatos();

                Buzon buzonEntrada = cuenta.BuzonEntrada;
                Buzon buzonSalida = cuenta.BuzonSalida;
                buzonEntrada.RecuperarDatos();
                buzonSalida.RecuperarDatos();

                //linkeo los padres del buzon de entrada
                foreach(ObjetoBuzon objetoA in buzonEntrada.ObjetosBuzon)
                {
                    foreach(ObjetoBuzon objetoB in buzonEntrada.ObjetosBuzon)
                    {
                        if (objetoB.GetType().Name.ToString() == "Carpeta") 
                        {
                            if (objetoA.GetType().Name.ToString() == "Carpeta"
                                && ((Carpeta)objetoA).Padre.Oid.Equals(objetoB.Oid))
                            {
                                ((Carpeta)objetoA).Padre = (Carpeta)objetoB;
                            }
                            if (objetoA.GetType().Name.ToString() == "Mensaje"
                                && ((Mensaje)objetoA).CarpetaPadre.Oid.Equals(objetoB.Oid))
                            {
                                ((Mensaje)objetoA).CarpetaPadre = (Carpeta)objetoB;
                            }
                        }
                    }
                }                
                foreach (ObjetoBuzon objetoA in buzonSalida.ObjetosBuzon)
                {
                    foreach (ObjetoBuzon objetoB in buzonSalida.ObjetosBuzon)
                    {
                        if (objetoB.GetType().Name.ToString() == "Carpeta")
                        {
                            if (objetoA.GetType().Name.ToString() == "Carpeta"
                                && ((Carpeta)objetoA).Padre.Oid.Equals(objetoB.Oid))
                            {
                                ((Carpeta)objetoA).Padre = (Carpeta)objetoB;
                            }
                            if (objetoA.GetType().Name.ToString() == "Mensaje"
                                && ((Mensaje)objetoA).CarpetaPadre.Oid.Equals(objetoB.Oid))
                            {
                                ((Mensaje)objetoA).CarpetaPadre = (Carpeta)objetoB;
                            }
                        }
                    }
                }
            }
            
            //Voy a linkear los mensajes con sus cuentas destinatarias
            foreach (Cuenta cuenta in cuentas)
            {
                foreach (ObjetoBuzon mensaje in cuenta.BuzonEntrada.ObjetosBuzon)
                {
                    if (mensaje.GetType().Name.ToString() == "Mensaje")
                    {
                        ((Mensaje)mensaje).RecuperarDatos();
                        foreach (Cuenta dest in ((Mensaje)mensaje).Destinatarios)
                        {
                            Cuenta destinatario = dest;
                            foreach (Cuenta posibleDest in cuentas)
                            {
                                if (destinatario.Oid.Equals(posibleDest.Oid))
                                {
                                    destinatario = posibleDest;
                                }
                            }
                        }
                    }
                    
                }
                foreach (ObjetoBuzon mensaje in cuenta.BuzonSalida.ObjetosBuzon)
                {
                    if (mensaje.GetType().Name.ToString() == "Mensaje")
                    {
                        ((Mensaje)mensaje).RecuperarDatos();
                        foreach (Cuenta dest in ((Mensaje)mensaje).Destinatarios)
                        {
                            Cuenta destinatario = dest;
                            foreach (Cuenta posibleDest in cuentas)
                            {
                                if (destinatario.Oid.Equals(posibleDest.Oid))
                                {
                                    destinatario = posibleDest;
                                }
                            }
                        }
                    }

                }
            }
            cuentasList = cuentas;
        }

        public Cuenta Login(String usuario, String contrasenia, bool common)
        {
            if (!common && usuario.Equals("admin") && contrasenia.Equals("admin"))
            {
                Cuenta c = new Cuenta();
                Usuario u = new Usuario();
                u.Nombre = "Administrador";
                u.Apellido = "Administrador";
                c.NombreCuenta = "Administrador";
                c.Usuario = u;
                return c;
            }
            else
            {
                if (common)
                {
                    Cuenta login = new Cuenta();
                    login.NombreCuenta = usuario;
                    login.Contrasenia = contrasenia;
                    foreach (Cuenta cuenta in cuentasList)
                    {
                        if (login.NombreCuenta.Equals(cuenta.NombreCuenta)
                            && login.Contrasenia.Equals(cuenta.Contrasenia))
                        {
                            login = cuenta;  
                        }
                    }
                    if (login.Oid != null)
                    {
                        return login;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
        }

        /// <summary>
        /// Metodos del administrador
        /// </summary>
        
        public void CrearCuenta(String cedula, String nombre, String apellido, 
                                String nombreCuenta, String contrasenia)
        {
            //Busco el usuario por la cedula
            // Si no lo consigo
            Usuario user = new Usuario();            
            //user.Cedula = cedula;
            //user.RecuperarDatos();

            //if (user.Oid == null) {
                user.Cedula = cedula;
                user.Nombre = nombre;
                user.Apellido = apellido;
            //}
            //Guardo el usuario
            user.Agregarse();

            Buzon buzonEntrada = Buzon.CreateBuzonEntrada();
            buzonEntrada.Agregarse();
            Buzon buzonSalida = Buzon.CreateBuzonSalida();
            buzonSalida.Agregarse();
            
            Cuenta cuenta = new Cuenta();
            cuenta.Usuario = user;
            cuenta.BuzonEntrada = buzonEntrada;
            cuenta.BuzonSalida = buzonSalida;
            cuenta.NombreCuenta = nombreCuenta + "@da2.com";
            cuenta.Contrasenia = contrasenia;
            cuenta.Agregarse();

            cuentasList.Add(cuenta);
        }

        public List<OPersistente> ObtenerCuentas()
        {
            return this.CuentasList;
        }

        public void EliminarCuenta(Cuenta cuenta)
        {
            cuenta.Eliminada = true;
            cuenta.Elminarse();
            Cuenta aBorrar = null;
            foreach (Cuenta c in cuentasList)
            {
                if (c.NombreCuenta.Equals(cuenta.NombreCuenta))
                {
                    aBorrar = c;
                }
            }
            cuentasList.Remove(aBorrar);
        }

        /// <summary>
        /// Metodos del correo de usuarios
        /// </summary>
  
        public void MarcarMensajeComoLeido(Mensaje mensaje)
        {
            ICommand commando = new CommandMensaje(mensaje, null, CommandMensaje.Metodos.MarcarComoLeido);
            commando.Execute();
            Commandos.Add(commando);
        }

        public void MarcarMensajeComoNoLeido(Mensaje mensaje)
        {
            ICommand commando = new CommandMensaje(mensaje, null, CommandMensaje.Metodos.MarcarComoNoLeido);
            commando.Execute();
            Commandos.Add(commando);
        }

        public void OrganizarBuzonPorRegla(Buzon buzon, Regla regla)
        {
            List<Object> reglas = new List<Object>();
            reglas.Add(regla);
            ICommand commando = new CommandBuzon(buzon, reglas, CommandBuzon.Metodos.AplicarRegla);
            commando.Execute();            
            Commandos.Add(commando);
        }

        public Mensaje MandarMensaje(String remitente, String destinatarios, String asunto, String contenido)
        {
            Cuenta remitenteCuenta = BuscarCuenta(remitente);
            List<Cuenta> destinatariosCuentas = new List<Cuenta>();

            char[] separadores = {','};
            string[] destinatariosList = destinatarios.Split(separadores);
            for(int i = 0; i < destinatariosList.Length; i++)
            {
                Cuenta destinatario = BuscarCuenta(destinatariosList[i].Trim());

                if (destinatario == null)
                    return null;

                destinatariosCuentas.Add(destinatario);

            }

            Mensaje msjNuevo = new Mensaje(remitenteCuenta, destinatariosCuentas, asunto, contenido);
            msjNuevo.BuzonPadre = remitenteCuenta.BuzonSalida;
            msjNuevo.Agregarse();
            remitenteCuenta.BuzonSalida.ObjetosBuzon.Add(msjNuevo);
            
            Mensaje msjDestinatario = null;

            foreach (Cuenta c in destinatariosCuentas)
            {
                msjDestinatario = new Mensaje(remitenteCuenta, destinatariosCuentas, asunto, contenido);
                msjDestinatario.BuzonPadre = c.BuzonEntrada;
                msjDestinatario.Agregarse();
                c.BuzonEntrada.ObjetosBuzon.Add(msjDestinatario);

            }

            return msjNuevo;
        }

        public Buzon RecibirMensajes(String cuentaStr)
        {
            Cuenta cuenta = BuscarCuenta(cuentaStr);
            return cuenta.BuzonEntrada;
        }

        private Carpeta CrearCarpeta(String nombre, Carpeta padre, Buzon buzon)
        {
            Carpeta carpeta = new Carpeta(nombre, padre, buzon);
            return carpeta;   
        }

        public Carpeta CrearCarpetaEnCarpeta(String nombre, Carpeta padre, string cuentaUsuario, String tipoBuzon)
        {
            Cuenta cuenta = BuscarCuenta(cuentaUsuario);
            Buzon buzon = null;
            if (tipoBuzon.Equals(Buzon.Entrada))
                buzon = cuenta.BuzonEntrada;
            else
                buzon = cuenta.BuzonSalida;

            Carpeta carpetaPadre = BuscarCarpeta(padre, cuentaUsuario, tipoBuzon);
            Carpeta carpeta = CrearCarpeta(nombre, carpetaPadre,buzon);
            carpetaPadre.AgregarObjetoBuzon(carpeta);
            //List<Object> parametros = new List<Object>();
            //parametros.Add(carpeta);
            //ICommand commando = new CommandCarpeta(padre, parametros, CommandCarpeta.Metodos.AgregarObjetoBuzon);
            //commando.Execute();
            //Commandos.Add(commando);
            return carpeta;
        }

        public Carpeta CrearCarpetaEnBuzon(String nombre,Buzon buzon, string cuenta)
        {
            Carpeta carpeta = null;
            Cuenta cuentaSistema = BuscarCuenta(cuenta);
            if (buzon.Tipo.Equals(Buzon.Entrada))
            {
                carpeta = CrearCarpeta(nombre, null,cuentaSistema.BuzonEntrada);
                cuentaSistema.BuzonEntrada.ObjetosBuzon.Add(carpeta);
            }
            else
            {
                carpeta = CrearCarpeta(nombre, null, cuentaSistema.BuzonSalida);
                cuentaSistema.BuzonSalida.ObjetosBuzon.Add(carpeta);
            }
            //List<Object> parametros = new List<Object>();
            //parametros.Add(carpeta);
            //ICommand commando = new CommandBuzon(buzon, parametros, CommandBuzon.Metodos.CrearCarpeta);
            //commando.Execute();
            //Commandos.Add(commando);

            return carpeta;
        }

        public bool EliminarCarpetaEnCarpeta(Carpeta carpetaHija, Carpeta carpetaPadre)
        {
            List<Object> parametros = new List<Object>();
            parametros.Add(carpetaHija);
            ICommand commando = new CommandCarpeta(carpetaPadre, parametros, CommandCarpeta.Metodos.EliminarObjetoBuzon);
            commando.Execute();
            Commandos.Add(commando);
            return true;
        }

        public bool EliminarCarpetaEnBuzon(Carpeta carpetaHija, Buzon buzonPadre)
        {
            List<Object> parametros = new List<Object>();
            parametros.Add(carpetaHija);
            ICommand commando = new CommandBuzon(buzonPadre, parametros, CommandBuzon.Metodos.EliminarCarpeta);
            commando.Execute();
            Commandos.Add(commando);
            return true;
        }



        private Cuenta BuscarCuenta(String cuentaUsuario)
        {
            Cuenta cuenta = null;
            if (cuentaUsuario != null) 
            {
                foreach (Cuenta c in CuentasList)
                {
                    if (c.NombreCuenta.ToUpper().Equals(cuentaUsuario.ToUpper()))
                    {
                        cuenta = c;
                        break;
                    }
                }
            }
            return cuenta;
        }

        private Carpeta BuscarCarpeta(Carpeta carpetaPadre, String cuentaUsuario, String tipoBuzon)
        {
            Cuenta cuenta = BuscarCuenta(cuentaUsuario);
            Carpeta encontrada = null;
            Buzon buzon = null;
            if (tipoBuzon.Equals(Buzon.Entrada))
                buzon = cuenta.BuzonEntrada;
            else
                buzon = cuenta.BuzonSalida;

            foreach (ObjetoBuzon objBuzon in buzon.ObjetosBuzon)
            {
                if(objBuzon.GetType().Name.Equals("Carpeta"))
                {
                    if (objBuzon.Equals(carpetaPadre))
                        return (Carpeta)objBuzon;
                    else
                    {
                        encontrada = BuscarCarpeta((Carpeta)objBuzon, carpetaPadre);
                        if (encontrada != null)
                            return encontrada;
                    }
                }
            }
            return null;
        }

        private Carpeta BuscarCarpeta(Carpeta carpetaPadre, Carpeta carpetaBuscada)
        {
            Carpeta encontrada = null;
            foreach (ObjetoBuzon objBuzon in carpetaPadre.ObjetosBuzon)
            {
                if (objBuzon.GetType().Name.Equals("Carpeta"))
                {
                    if (objBuzon.Equals(carpetaBuscada))
                        return (Carpeta)objBuzon;
                    else
                    {
                        encontrada = BuscarCarpeta((Carpeta)objBuzon, carpetaBuscada);
                        if (encontrada != null)
                            return encontrada;
                    }
                }
            }
            return null;
        }

        public Buzon TraerBuzon(String cuenta, String tipo)
        {
            Cuenta c = BuscarCuenta(cuenta);
            if (tipo.ToLower().Equals("entrada"))
                return c.BuzonEntrada;
            else
                return c.BuzonSalida;
        }
        


    }
}
